/**
 ** os - Operating system interface
 *
 * The os module interfaces with the oj file service to provide file system operations.
 *
 */

define('oj/os', ['oj/remote'], function (remote) {
    'use strict';

    var os = {
        /* Properties */
        environ: {
            cwd: '/'
        },
        
        /* Functions */
        identity: function (returnUrl, callback) {},
        logout  : function (destUrl, callback) {},
        system  : function (path, commands, callback) {},
        read    : function (path, callback ) {},
        write   : function (path, content, callback) {},
        chdir   : function (path, callback) {},
        mkdir   : function (path, callback) {},
        rmdir   : function (path, callback) {},
        listdir : function (path, callback) {},
        move    : function (src, dst, callback) {},
        remove  : function (path, callback) {},
        concat  : function (paths, clean, callback) {},
        path: {
            abspath : function (path) {},
            isdir   : function (path, callback) {},
            basename: function (path) {},
            dirname : function (path) {}
        }
    };
    
    
    os.system = function(path, commands, callback) {
        /**
         *> os.system('path', [commands], callback)
         * 
         * Execute a list of server commands.
         * 
         */
        
        remote.jsonp(path, 'P/', commands.join('&'), callback);
    };
    
    
    os.identity = function(destUrl, callback) {
        /**
         *> os.identity('destUrl', callback)
         * 
         * Get user identity.
         * 
         */
        
        os.system('/', ['I/' + destUrl], callback);
    };
    
    
    os.logout = function(destUrl, callback) {
        /**
         *> os.logout('destUrl', callback)
         * 
         * Logs user out.
         * 
         */
        
        os.system('/', ['E/' + destUrl], callback);
    };
    
    
    os.read = function(path, callback) {
        /**
         *> os.read('path', callback)
         * 
         * Reads a path from the server.
         * 
         */
        os.system(path, ['R/'], callback);
    };
    
    
    os.write = function(path, content, callback) {
        /**
         *> os.write('path', 'content', callback)
         * 
         * Write content to path.
         * 
         */
        
        os.system(path, ['W/' + content], callback);
    };
    
    
    os.chdir = function(path, callback) {
        /**
         *> os.chdir('path', callback)
         * 
         * Changes the current working directory.
         * 
         */
        
        path = os.path.abspath(path + '/');
        os.read(path, function(read) {
            if (!oj.isError(read)) {
                os.environ.cwd = path;
            }
            oj.respond(callback, read);
        });
    };
    
    
    os.mkdir = function(path, callback) {
        /**
         *> os.mkdir('path', callback)
         * 
         * Creates a new directory.
         * 
         */
        
        os.system(os.path.abspath(path + '/'), ['M/'], callback);
    };
    
    
    os.rmdir = function(path, callback) {
        /**
         *> os.rmdir('path', callback)
         * 
         * Removes a directory.
         * 
         */
        os.system(os.path.abspath(path + '/'), ['X/'], callback);
    };
    
    
    os.listdir = function(path, callback) {
        /**
         *> os.listdir('path', callback)
         * 
         * Returns a list of files and directories.
         * 
         */
        
        if (Object.type(path) === 'Undefined' || path === '') {
            path = '.';
        }
        
        os.read(os.path.abspath(path + '/'), function (m) {
            try {
                m = JSON.parse(m);
            } catch (err) {}
            oj.respond(callback, m);
        });
    };
    
    
    os.move = function(src, dst, callback) {
        /**
         *> os.move('src', 'dst', callback)
         * 
         * Moves a file or directory from src to dst.
         * 
         */
        os.system(os.path.abspath(src), ['N/' + os.path.abspath(dst)], callback);
    };
    
    
    os.remove = function(path, callback) {
        /**
         *> os.remove('path', callback)
         * 
         * Removes file at path.
         * 
         */
        
        os.system(os.path.abspath(path), ['D/'], callback);
    };
    
    
    os.concat = function(paths, clean, callback) {
        /**
         *> os.concat([paths], clean, callback)
         * 
         * Concatenates a list of files to one file.
         *
         *. os.concat( args, false, function (msg) {
         *.     var error = oj.isError(msg);
         *. });
         *
         */
        
        var path = os.path.abspath(paths.pop()),
            cmd = (clean) ? 'CR/' : 'C/',
            i = paths.length;
        
        while (--i) {
            paths[i] = os.path.abspath(paths[i]);
        }
        
        os.system(path, [cmd + paths.join('!')], callback);
    };
    
    
    os.path.abspath = function(path) {
        /**
         *> os.path.abspath('path')
         * 
         * Returns a normalised absolute path.
         * 
         */
        var p = (/^\//.test(path) ? path : os.environ.cwd + path).split('/'),
            abs = [],
            i = -1,
            result;

        while (++i < p.length) {
            if (p[i].length !== 0) {
                if (/^\.\.$/.test(p[i])) {
                    abs.pop();
                } else if (!/^\.$/.test(p[i])) {
                    abs.push(p[i]);
                }
            }
        }
        
        result = '/' + abs.join('/');
        
        if (path.lastIndexOf('/') === path.length - 1 && abs.length > 0) {
            result += '/';
        }
        
        return result;
    };
    
    
    os.path.isdir = function(path, callback) {
        /**
         *> os.path.isdir('path', callback)
         * 
         * Calls callback with true if path is an existing directory,
         * otherwise false.
         * 
         */
        
        os.read(os.path.abspath(path + '/'), function(m) {
            oj.respond(callback, !oj.isError(m));
        });
    };
    
    
    os.path.basename = function(path) {
        /**
         *> os.path.basename('path')
         * 
         * Return the base name of path.
         */
        
        if (/\/$/.test(path)) {
            return '';
        }
            
        if (path === '') {
            return null;
        }
        
        return path.split('/').pop();
    };
    
    
    os.path.dirname = function(path) {
        /**
         *> os.path.basename('path')
         * 
         * Return the base name of path.
         */
        
        if (/\/$/.test(path)) {
            return path;
        }
            
        if (path === '') {
            return null;
        }
        
        path = path.split('/');
        path.pop();
        
        return path.join('/') + '/';
    };
    
    
    return os;

});
